package verifycode

import (
	"math/rand"
	"strings"
)

func RandCode(chars string, idxBits, l int) string {
	//形成掩码
	idxMask := 1<<idxBits - 1
	// 63 位可以使用的最大组次数
	idxMax := 63 / idxBits
	// 利用string builder构建结果缓冲
	sb := strings.Builder{}
	sb.Grow(l)

	// 循环生成随机数
	// i 索引
	// cache 随机数缓存
	// remain 随机数还可以用几次
	for i, cache, remain := l-1, rand.Int63(), idxMax; i >= 0; {
		// 随机缓存不足，重新生成
		if remain == 0 {
			cache, remain = rand.Int63(), idxMax
		}
		// 利用掩码生成随机索引，有效索引为小于字符集合长度
		if idx := int(cache & int64(idxMask)); idx < len(chars) {
			sb.WriteByte(chars[idx])
			i--
		}
		// 利用下一组随机数位
		cache >>= idxBits
		remain--
	}
	return sb.String()
}
